/***************************************************************************
 *   Copyright (C) 2007 by Alexandre Masselot,,,   *
 *   alex@alex-laptop   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifndef BOLSPECTRUM_H
#define BOLSPECTRUM_H

#ifdef HAVE_BOOST_SERIALIZATION
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#else
#include <vector> // included by serialisers above
#endif

#ifdef HAVE_PROTOBUF
#ifdef _MSC_VER
// we don't create DLLs and thus don't need to pay attention to this warning
#pragma warning( disable: 4251 )
#endif
#include "runlcmsms.pb.h"
#endif

#include "peak.h"

using namespace std;
using namespace bol;
namespace bol {

  /**
  a collection of Peak


    @author Alexandre Masselot,,, <alex@alex-laptop>
  */
  template <class T>class Spectrum:public vector<T>{
      long long m_refid;
  public:
      Spectrum<T>():m_refid(0){};
      ~Spectrum(){
        for(size_t i=0; i<this->size(); i++){
          if((*this)[i]) delete (*this)[i];
        }
      };

      void setRefid(long long  theValue) {
        m_refid = theValue;
      }
      long long refid() const {
        return m_refid;
      }

    template<class U> friend ostream& operator<<(ostream& out, const Spectrum<U*>& sp);

#ifdef HAVE_BOOST_SERIALIZATION
      // *** BOOST serialisation code ***
    friend class boost::serialization::access; // gives access to serialisator
    template<class Archive> void serialize ( Archive & ar, const unsigned int version ) const
    {
        // base class serialisation - warning, as there are several variable, the order is critical...
        // ... well not for XML. But for most other archive types.

      // the peaks
      ar & boost::serialization::make_nvp("refid", m_refid);
      ar & boost::serialization::make_nvp("Peaks", boost::serialization::base_object<vector<T> > ( *this ));
    }
#endif

  };


#ifdef HAVE_PROTOBUF
  // CaptainBol uses pointers to indicate parent peak and parent spectrum
  // serializers uses index numbers
  // - boost does keep track and convert pointer by it self
  // - protobuf doesn't. We need a Pointer-to-Index mapper (or we need to do linear-scans)
  typedef map<const void*,size_t> Ptr2IndexMap;
  typedef boost::shared_ptr< Ptr2IndexMap > Ptr2IndexMapPtr;

  template<class U> bool static inline protobufwithmap (protobuf::RunLcmsms::Spectrum& pb, const Spectrum<U*>& sp, Ptr2IndexMapPtr spidx) {
    pb.clear_peak();
    for (typename Spectrum<U*>::const_iterator i=sp.begin(); i != sp.end(); i++) {
      // store in this spectrum's "Peak-to-index" 
      // which index each peak is
      (*spidx)[static_cast<const void *> (*i)] = pb.peak_size();

      // and serialize the peak itself
      (*(pb.add_peak())) << *(*i);
    }
    return true;
  }

  template<class U> bool static inline operator<<(protobuf::RunLcmsms::Spectrum& pb, const Spectrum<U*>& sp) {
    pb.clear_peak();
    for (typename Spectrum<U*>::const_iterator i=sp.begin(); i != sp.end(); i++) {
      (*(pb.add_peak())) << *(*i);
    }
    return true;
  }

  template<class U> bool operator>> (const protobuf::RunLcmsms::Spectrum& pb, Spectrum<U*>& sp) {
    sp.resize(pb.peak_size());
    for (int i = 0; i < pb.peak_size(); i++) {
      U* p = new U (pb.peak(i).moz(), 0, pb.peak(i).intensity());
          // the constructor set the M/Z and the intensity here, at allocation time
      pb.peak(i) >> (*p);
      sp[i] = p;
    }
    return true;
  }
#endif

  template<class U> ostream& operator<<(ostream& out, const Spectrum<U*>& sp){
    for (size_t i=0; i<sp.size(); i++)
      out<< *sp[i]<<"\n";
    return out;
  }


}

#endif
